package eu.webhib.extgui.controller.tree;

import eu.webhib.extgui.controller.intf.TreeDataProvider;
import eu.webhib.extgui.controller.list.ListController;
import eu.webhib.extgui.data.intf.DataItem;
import eu.webhib.extgui.update.TreeListUpdateMngr;
import org.apache.log4j.Logger;
import org.primefaces.event.*;
import org.primefaces.model.*;

/**
 * Manages a tree that is aware of an table list connected with the tree.
 * The selected item in the tree is signaled to the table list so the table list is able to update its view,
 * e.g. display the children of the item selected in the tree
 */
public class TreeControllerListConnected extends TreeController {

   private static final Logger log = Logger.getLogger(TreeControllerListConnected.class);
   /** reference to interconnected table list controller */
   private ListController listController;
   /** controls the partial updating of view components */
   private TreeListUpdateMngr treeListUpdate;

   /**
    * @param treeDataProvider the tree item provider
    * @param listController the controller of the interconnected list
    * @param treeListUpdate controls update of view components of the tree and the list component
    */
   public TreeControllerListConnected(TreeDataProvider treeDataProvider, ListController listController, TreeListUpdateMngr treeListUpdate) {
      super(treeDataProvider, treeListUpdate);
      assert (listController != null);
      assert (treeListUpdate != null);
      this.listController = listController;
      this.treeListUpdate = treeListUpdate;
   }

   /**
    * Tree listener called by view (framework) on node selection
    * @param event
    */
   @Override
   public void onNodeSelect(NodeSelectEvent event) {
      log.info("onNodeSelect: " + event.getTreeNode().getData().toString());

      /** tree node clicked by user */
      TreeNode clickedNode = event.getTreeNode();

      DataItem oldTableListParent = listController.getListParent();
      DataItem oldSelectedTableListItem = listController.getSelectedItem();

      /** data item from tree node */
      DataItem clickedItem = (DataItem) clickedNode.getData();
      /** if node is a leaf node */
      if (clickedNode.getChildren() == null || clickedNode.getChildren().isEmpty()) {
         /** change tree selection to parent tree node */
         clickedNode.setSelected(false);
         clickedNode.getParent().setSelected(true);
         setSelectedTreeNodeInternal(clickedNode.getParent());
         /** because of programmatically changed selection, need to update the tree view */
         treeListUpdate.markTreeUpdate();
      } else {
         setSelectedTreeNodeInternal(clickedNode);
      }

      /** table list: set preselected item in list */
      setPreselectedListItem(clickedItem);
      if (oldTableListParent != listController.getListParent()
              || oldSelectedTableListItem != listController.getSelectedItem()) {
         /** list parent or selected item in list have changed, need to update list component */
         treeListUpdate.markListUpdate();
      }
      /** hand over the marked (added) components for update */
      treeListUpdate.updateMarkedTargets();
   }

   /**
    * @see TreeController
    */
   @Override
   protected void setSelectedTreeNodeInternal(TreeNode selectedTreeNode) {
      log.info("setSelectedTreeNodeInternal: " + (selectedTreeNode == null ? "" : selectedTreeNode.getData().toString()));

      super.setSelectedTreeNodeInternal(selectedTreeNode);
      /** also signal to accompanied list:
       *  the data item of the now selected tree node is the list parent in the table list */
      listController.setListParent((DataItem) selectedTreeNode.getData());
   }

   /**
    * Internal helper method to set the data item that shall be preselected in the table list.
    * This is may be the parent list or an children of it
    * @param dataItem data item of the selected tree node
    */
   private void setPreselectedListItem(DataItem dataItem) {
      /** set preselected item at table list */
      if (dataItem == this.dataItemTreeRoot) {
         /** special handling if item root is clicked as this represents no real data item */
         listController.unselectItem();
      } else {
         /** the data item in the list underlying the clicked tree node */
         listController.setSelectedItem(dataItem);
      }
   }

   /**
    * @see TreeController
    */
   @Override
   public void onNodeUnselect(NodeUnselectEvent event) {
      log.info("onNodeUnselect: " + event.getTreeNode().getData().toString());

      super.onNodeUnselect(event);
      /** set selected item in list in accordance with current tree selection */
      setPreselectedListItem(getSelectedDataItem());
   }
}
